package org.zpmis.util;

import io.minio.*;
import io.minio.errors.*;

import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.zpmis.config.MinioConfig;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * minio 通用操作类
 */
@Component
public class MinioUtil {

    final static Logger logger = LoggerFactory.getLogger(MinioUtil.class);

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private MinioConfig minioConfig;

    /**
     * 默认桶
     */
    public final static  String DEFAUT_BUCKET="defaut";

    /**
     * 默认过去时间
     */
    public final static  int SHARE_EXPIRY_TIME_SECOND =  5*60;

    /**
     * 创建桶
     * @param bucketName 桶名称
     */
    public void createBucket(String bucketName) throws Exception {

        //桶不存在
        try {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())){
                //创建桶
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (ErrorResponseException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (InsufficientDataException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (InternalException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (InvalidKeyException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (InvalidResponseException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (IOException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (ServerException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        } catch (XmlParserException e) {
            logger.error("创建桶异常",e);
            throw new Exception("create bucket except");
        }

    }

    /**
     * 获取文件信息
     * @param bucketName 桶名
     * @param fileName 文件名
     * @return
     */
    public StatObjectResponse getObjectState(String bucketName, String fileName) throws Exception {
        try {
            return minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
        } catch (ErrorResponseException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (InsufficientDataException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (InternalException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (InvalidKeyException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (InvalidResponseException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (IOException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (ServerException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        } catch (XmlParserException e) {
            logger.error("获取文件信息异常",e);
            throw new Exception("get  file state except");
        }
    }

    /**
     * 上传文件
     * @param bucketName 桶名
     * @param fileName 文件名
     * @param contentType
     * @param filePath 文件全路径
     * @return 文件名称
     * @throws Exception
     */
    public String uploadObject(String bucketName,String fileName, String filePath,String contentType) throws Exception {
        //桶名为空使用默认名称
        if (StringUtils.isEmpty(bucketName)){
            bucketName = DEFAUT_BUCKET;
        }

        try {
            UploadObjectArgs uploadObjectArgs  = UploadObjectArgs.builder()
                    .filename(filePath)
                    .object(fileName)
                    .contentType(contentType)
                    .bucket(bucketName)
                    .build();
            ObjectWriteResponse objectWriteResponse = minioClient.uploadObject(uploadObjectArgs);
            return objectWriteResponse.object();
        } catch (IOException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (XmlParserException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (ServerException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InsufficientDataException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InvalidKeyException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InvalidResponseException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (ErrorResponseException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InternalException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        }

    }

    /**
     * 上传文件
     * @param bucketName 桶名
     * @param fileName 文件名
     * @param inputStream 文件流
     * @param contentType
     * @return 文件名
     * @throws Exception
     */
    public String  uploadStream(String bucketName,String fileName ,InputStream inputStream, String contentType) throws Exception {

        //桶名为空使用默认名称
        if (StringUtils.isEmpty(bucketName)){
            bucketName = DEFAUT_BUCKET;
        }

        try {
            PutObjectArgs putObjetcArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream,inputStream.available(),-1)
                    .contentType(contentType)
                    .build();
            ObjectWriteResponse  objectWriteResponse = minioClient.putObject(putObjetcArgs);
            return  objectWriteResponse.object();
        } catch (ErrorResponseException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InsufficientDataException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InternalException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InvalidKeyException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (InvalidResponseException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (IOException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (ServerException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        } catch (XmlParserException e) {
            logger.error("上传文件异常",e);
            throw new Exception("upload file except");
        }

    }

    /**
     * 下载文件
     * @param fileName 文件名
     * @param downloadFilePath 下载的文件全路径
     * @param bucketName 桶名
     */
    public void download(String fileName,String downloadFilePath, String bucketName) throws Exception {
        DownloadObjectArgs downloadObjectArgs = DownloadObjectArgs.builder()
                .object(fileName)
                .filename(downloadFilePath)
                .bucket(bucketName)
                .build();
        try {
            minioClient.downloadObject(downloadObjectArgs);
        } catch (ErrorResponseException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InsufficientDataException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InternalException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InvalidKeyException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InvalidResponseException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (IOException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (ServerException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (XmlParserException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        }
    }

    /**
     * 下载文件
     * @param fileName 文件名
     * @param bucketName 桶名
     * @return
     */
    public InputStream get(String fileName, String bucketName) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build();
        try {
            InputStream  stream = minioClient.getObject(getObjectArgs);
            return  stream;
        } catch (ErrorResponseException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InsufficientDataException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InternalException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InvalidKeyException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (InvalidResponseException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (IOException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (ServerException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        } catch (XmlParserException e) {
            logger.error("下载文件异常",e);
            throw new Exception("download file except");
        }
    }

    /**
     * 删除文件
     * @param fileName 文件名
     * @param bucketName 桶名
     * @throws Exception
     */
    public void remove(String fileName, String bucketName) throws Exception {
        RemoveObjectArgs removeObjectArgs =   RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (ErrorResponseException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (InsufficientDataException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (InternalException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (InvalidKeyException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (InvalidResponseException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (IOException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (ServerException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        } catch (XmlParserException e) {
            logger.error("删除文件异常",e);
            throw new Exception("remove file except");
        }
    }

    /**
     * 分享链接
     * @param bucketNme 桶
     * @param fileName 文件名
     * @param shareExpiryTime 分享过期时间 s
     * @return
     */
    public String shareUrl(String bucketNme, String fileName, int shareExpiryTime) throws Exception {
        try {

          String shareUri =   minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketNme)
                    .object(fileName)
                    .expiry(shareExpiryTime)
                    .build());
          //判断网关地址
            if (!StringUtils.isEmpty(minioConfig.getGatewayAddress())){
                //替换地址
                int indexBegin = shareUri.indexOf("//")+2;

                shareUri = minioConfig.getGatewayAddress() + shareUri.substring(shareUri.indexOf("/",indexBegin),shareUri.length());
            }
            return shareUri;
        } catch (ErrorResponseException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (InsufficientDataException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (InternalException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (InvalidKeyException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (InvalidResponseException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (IOException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (NoSuchAlgorithmException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (XmlParserException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        } catch (ServerException e) {
            logger.error("分享文件异常",e);
            throw new Exception("share file except");
        }
    }

    /**
     * 生产随机文件名
     * @param originalFile 原文件名称
     * @return 新文件名
     */
    public String generateRandomFileName(String originalFile){
        Assert.notNull(originalFile,"originalFile is null");
        String ext = originalFile.substring(originalFile.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString().replace("-","")+ext;
        return fileName;
    }
}
